﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Org.BouncyCastle;
using System.Web.Script.Serialization;

namespace NotifyApplication.Controllers
{
    class SignatureUtil
    {
        public static String GetRsaSign(String data, String privateKey, String charset)
        {
            byte[] bData = Encoding.GetEncoding(charset).GetBytes(data);
            RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider(2048);
            myRSA.FromXmlString(RSAKeyConvert.RSAPrivateKeyJava2DotNet(privateKey));
            bData = myRSA.SignData(bData, "SHA256");
            return Convert.ToBase64String(bData);
        }

        public static String GetSignContent(Dictionary<String, String> sortedParams)
        {
            StringBuilder content = new StringBuilder();
            var dicSort = from objDic in sortedParams orderby objDic.Key select objDic;
            foreach (KeyValuePair<string, string> kvp in dicSort)
            {
                String key = kvp.Key;
                String value = kvp.Value;
                if (null != key && null != value)
                {
                    content.Append(key + "=" + value + "&");
                }
                
            }
            if (content.Length != 0)
            {
                content.Remove(content.Length - 1, 1);
            }
            return content.ToString();
        }

        public static bool GetRsaCheck(String data, String sign, String publicKey, String charset)
        {
            byte[] bData = Encoding.GetEncoding(charset).GetBytes(data);
            byte[] bSign = Convert.FromBase64String(sign);

            RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider(2048);
            myRSA.FromXmlString(RSAKeyConvert.RSAPublicKeyJava2DotNet(publicKey));

            return myRSA.VerifyData(bData,new SHA256CryptoServiceProvider(), bSign);
        }

        public static string SignMethod(Dictionary<string, string> requestTransactionParams, string privateKey)
        {
            Dictionary<string, string> requestPublicParams = new Dictionary<string, string>();
            string requestStr = null;
            //公共请求参数
            requestPublicParams.Add("version", "0.0.1");    //版本号，固定为0.0.1(必传字段)
            requestPublicParams.Add("encoding", "UTF-8");   //编码方式，固定为UTF-8(必传)
            requestPublicParams.Add("signMethod", "01");    //签名方法，固定为01，表示签名方式为RSA2(必传)
            
            JavaScriptSerializer jss = new JavaScriptSerializer();
            requestPublicParams.Add("biz_content", jss.Serialize(requestTransactionParams));

            System.Diagnostics.Debug.WriteLine("加签前的报文内容：" + jss.Serialize(requestPublicParams));

            //对待加签内容进行排序拼接
            string signContent = SignatureUtil.GetSignContent(requestPublicParams);
            //加签
            requestPublicParams.Add("sign", SignatureUtil.GetRsaSign(signContent, privateKey, "UTF-8"));

            requestStr = jss.Serialize(requestPublicParams);

            System.Diagnostics.Debug.WriteLine("加签后的报文内容：" + requestStr);
            return requestStr;
        }

        public static bool CheckSign(string str, string publicKey)
        {
            System.Diagnostics.Debug.WriteLine("要验签的报文内容：" + str);
            JavaScriptSerializer jss = new JavaScriptSerializer();
            Dictionary<string, string> responseBodyMap = jss.Deserialize<Dictionary<string, string>>(str);
            string sign = responseBodyMap["sign"];
            if (sign == null)
            {
                System.Diagnostics.Debug.WriteLine("报文验签失败1!");
                return false;
            }
            responseBodyMap.Remove("sign");
            string contentStr = SignatureUtil.GetSignContent(responseBodyMap);
            bool result = SignatureUtil.GetRsaCheck(contentStr, sign, publicKey, "UTF-8");

            if (result) {
                System.Diagnostics.Debug.WriteLine("报文验签成功!");
            } else {
                System.Diagnostics.Debug.WriteLine("报文验签失败2!");
            }
            return result;
        }

        public static Dictionary<string, string> str2Map(string str)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            string[] results = str.Split(new[]{"&"}, StringSplitOptions.None);
            if (results != null && results.Length > 0) {
                for (int var = 0; var < results.Length; ++var) {
                    String pair = results[var];
                    String[] kv = pair.Split(new[]{"="}, 2, StringSplitOptions.None);
                    if (kv != null && kv.Length == 2) {
                        result.Add(kv[0], kv[1]);
                    }
                }
            }
            return result;
        }
    }
}
